/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package SocketServer;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Santos
 */
public class ServidorSocketControl implements Runnable {

    private ServidorSocketModel model = new ServidorSocketModel();
    private ServidorSocketDAO dao = new ServidorSocketDAO();

    /**
     * Construtor que recebe por referencia o endereço de memoria do socket
     * cliente
     *
     * @param socketCliente
     */
    public ServidorSocketControl(Socket socketCliente) {
        model.setSocketCliente(socketCliente);
    }

    /**
     * Metodo responsável por processar a conexão entre o servidor e o cliente
     * Essa está preparada para tratar cada mensagem de texto enviada pelo
     * cliente e responder conforme o mesmo espera
     *
     * @throws java.io.IOException
     * @throws java.lang.ClassNotFoundException
     */
    public void processConnection() throws IOException, ClassNotFoundException {
        String message = "";
        //enviar mensagem para o cliente

        do {
            //lê uma nova mensagem
            message = getMensagemCliente();
            //verifica se chama a mensagem de instrução do jogo
            if (message.equals("instrucao")) {
                getMensagemApresentacao();
            }
            //verifica quantidade de respontas por jogo
            if (message.equals("quantires")) {
                enviarMensagemCliente("3" + model.getQuantidadeJogadas());
            }
            //verifica quais são os tipos de operação selecioado pelo usuário
            if (message.substring(0, 9).equals("operadorS")) {
                model.setSoma(message.substring(9, 10));
                model.setSubtracao(message.substring(10, 11));
                model.setMultiplicacao(message.substring(11, 12));
                model.setDivisao(message.substring(12, 13));
            }
            //gera numeros aleatorios para as operações
            if (message.equals("gerarNume")) {
                getGerarNumeroAleatorio();
            }
            //retornar um operador qualquer quando solicitado a partir da seleção do usuário
            if (message.equals("operadorJ")) {
                getOperacaoAleatoria();
            }
            //recebe o nome do jogador
            if (message.substring(0, 9).equals("nomeJogad")) {
                model.setNomeUsuario(message.substring(9, message.length()));
            }
            //recebe a data inicial do jogo
            if (message.substring(0, 9).equals("dataInici")) {
                model.setDataInicio(message.substring(9, message.length()));
            }
            //recebe a hora inicial do jogo
            if (message.substring(0, 9).equals("horaInici")) {
                model.setHoraInicio(message.substring(9, message.length()));
            }
            //recebe a quantidade correta de questões
            if (message.substring(0, 9).equals("qtdCorret")) {
                model.setTotalAcertos(Integer.parseInt(message.substring(9, message.length())));
            }
            //recebe a quantidade incorreta de questões
            if (message.substring(0, 9).equals("qtdIncorr")) {
                model.setTotalErros(Integer.parseInt(message.substring(9, message.length())));
                //ação de inserir no banco de dados
                model.setActionScript("I");
                //executa metodo de persistir os dados
                dao.GravarDados(model);
            }
            //retornar a quantidade de itens na lista de resultado daquele momento
            if (message.substring(0, 9).equals("tamanhoLi")) {
                enviarMensagemCliente("7" + dao.ConsultarDados().size());
            }

            if (message.equals("rankingJo")) {
                enviarMensagemCliente("8Nome:        Data       :      Qtd Acertos      :   Qtd Erros");
                /*Enviar mensagem para o cliente*/
                for (ServidorSocketModel rankJogador : dao.ConsultarDados()) {
                    enviarMensagemCliente(rankJogador.toString());
                }
                //Fecha conexão com o cliente
                closeConnection(model);
            }
            //sair do while com "rankingJo" sendo ela a ultima operação do cliente
        } while (!message.equals("rankingJo"));
    }

    public String getMensagemCliente() throws IOException, ClassNotFoundException {
        return (String) model.getEntrada().readObject();
    }

    /**
     * Envia mensagem para o cliente socket
     *
     * @param message
     * @throws IOException
     */
    public void enviarMensagemCliente(Object message) throws IOException {
        model.getSaida().writeObject(message);
        model.getSaida().flush();
    }

    /**
     * Metodo responsável por obter fluxos para enviar e receber dados
     *
     * @param client socket cliente
     * @throws IOException
     */
    public void getStreams(Socket client) throws IOException {
        /**
         * configura o fluxo de saída para objetos passa para a variavel saida o
         * endereço do socket cliente e trabalha-se sobre essa variavel, pois já
         * possúi o endereço de memoria do socket
         */
        model.setSaida(new ObjectOutputStream(client.getOutputStream()));
        model.getSaida().flush();

        ///configura o fluxo de entrada para objetos
        model.setEntrada(new ObjectInputStream(client.getInputStream()));
        System.out.println("Entrada e Saída de dados estabelecida");
    }

    /**
     * Metodo responsável por gerar as operações aleatoriamente e com base nas
     * opções que o cliente selecionou utilizando a tabela verdade
     *
     * @throws IOException
     */
    private void getOperacaoAleatoria() throws IOException {
        /*
         A	B	C	D    Operador
         1	1	1	1	+
         1	1	1	0	-
         1	1	0	1	*
         1	1	0	0	/
         1	0	1	1	+
         1	0	1	0	-
         1	0	0	1	*
         1	0	0	0	/
         0	1	1	1	+
         0	1	1	0	-
         0	1	0	1	*
         0	1	0	0	/
         0	0	1	1	+
         0	0	1	0	-
         0	0	0	1	*
         0	0	0	0	/
         */
        Random numeroRandom = new Random();
        boolean operacaoA = numeroRandom.nextBoolean();
        boolean operacaoB = numeroRandom.nextBoolean();
        boolean operacaoC = numeroRandom.nextBoolean();
        boolean operacaoD = numeroRandom.nextBoolean();

        String operacao = "9";
        if (!model.getSoma().equals("N")) {
            if ((operacaoA == true && operacaoB == true && operacaoC == true && operacaoD == true)
                    || (operacaoA == true && operacaoB == false && operacaoC == true && operacaoD == true)
                    || (operacaoA == false && operacaoB == true && operacaoC == true && operacaoD == true)
                    || (operacaoA == false && operacaoB == false && operacaoC == true && operacaoD == true)) {
                operacao = operacao.concat("+");
            }
        }
        if (!model.getSubtracao().equals("N")) {
            if ((operacaoA == true && operacaoB == true && operacaoC == true && operacaoD == false)
                    || (operacaoA == true && operacaoB == false && operacaoC == true && operacaoD == false)
                    || (operacaoA == false && operacaoB == true && operacaoC == true && operacaoD == false)
                    || (operacaoA == false && operacaoB == false && operacaoC == true && operacaoD == false)) {
                operacao = operacao.concat("-");
            }
        }
        if (!model.getMultiplicacao().equals("N")) {
            if ((operacaoA == true && operacaoB == true && operacaoC == false && operacaoD == true)
                    || (operacaoA == true && operacaoB == false && operacaoC == false && operacaoD == true)
                    || (operacaoA == false && operacaoB == true && operacaoC == false && operacaoD == true)
                    || (operacaoA == false && operacaoB == false && operacaoC == false && operacaoD == true)) {
                operacao = operacao.concat("*");
            }
        }
        if (!model.getDivisao().equals("N")) {
            if ((operacaoA == true && operacaoB == true && operacaoC == false && operacaoD == false)
                    || (operacaoA == true && operacaoB == false && operacaoC == false && operacaoD == false)
                    || (operacaoA == false && operacaoB == true && operacaoC == false && operacaoD == false)
                    || (operacaoA == false && operacaoB == false && operacaoC == false && operacaoD == false)) {
                operacao = operacao.concat("/");
            }
        }
        if (operacao.equals("9")) {
            getOperacaoAleatoria();
        } else {
            System.out.println("Operador selecionado: " + operacao);
            enviarMensagemCliente(operacao);
        }
    }

    /**
     * Metodo responsável por retornar a mensagem de apresentação para o usuário
     *
     * @throws IOException
     */
    private void getMensagemApresentacao() throws IOException {
        enviarMensagemCliente("0Bem Vindo ao Jogo das Operações Básicas da Álgebra!!!\n\n"
                + "Nesse jogo você poderá testar os seus conhecimentos relacionados as operações\n"
                + "matemáticas básicas que conhecemos. São elas a Adição(+), Subtração(-), Multiplicação(*) e Divisão(/)."
                + "\n\n"
                + "Instruções do Jogo: \n"
                + "1 - Você pode selecionar um ou mais operadores( (+) (-) (*) (/) ) para resolver os problemas que serão exibidos.\n"
                + "2 - Fique atendo ao operador da equação, pois ele será escolhido aleatóriamente pelo nosso servidor.\n"
                + "3 - Caso desista da seleção dos operadores, você pode clicar no botão Limpar para desfazer a seleção.\n"
                + "4 - Tendo certeza da seleção dos operadores, clicar no botão Iniciar.\n"
                + "5 - Após clicar no botão Iniciar, o servidor irá escolher números aleatóriamente entre 0 e 10 para você resolver a operação.\n"
                + "6 - Apresentado o problema na tela, você deverá preencher o campo resultado e preecionar a tecla ENTER ou clicar no botão Enviar para submeter o resultado.\n"
                + "7 - A cada jogo você deverá responder " + model.getQuantidadeJogadas() + " perguntas em sequência.\n"
                + "8 - Caso não queira continuar a partida em curso, clicar no botão Desistir para o sistema para o jogo.\n"
                + "9 - Ao final de cada jogo, será possível visualizar o Ranking dos resultado de cada jogador.\n"
                + "10 - Em caso de operações com divisão, informe no resultado apenas a parte inteira.\n"
                + "\n\n"
                + "Boa Sorte!");
    }

    /**
     * Metodo responsável por gerar um numero aleatório
     *
     * @throws IOException
     */
    private void getGerarNumeroAleatorio() throws IOException {
        //gerar um numero aleatorio interior dentro do intervalor de 1 até quantidadeConta
        int i = (int) (1 + Math.random() * 10);
        System.out.println("numero gerado servidor: " + i);
        String numero = String.valueOf(i);
        enviarMensagemCliente("1" + numero);
    }

    /**
     * Metodo responsável por fechar o fluxo de dados entre o servidor e o
     * cliente
     *
     * @param model
     * @throws IOException
     */
    public void closeConnection(ServidorSocketModel model) throws IOException {
        model.getEntrada().close();
        model.getSaida().close();
        model.getSocketCliente().close();
    }

    /**
     * Metodo responsável por recepcionar a instancia da classe de controle
     * iniciar o metodo reponsável por manter a conexão com as duas pontas de
     * comunicação
     */
    @Override
    public void run() {
        try {
            getStreams(model.getSocketCliente());
            if (!model.getSocketCliente().isClosed()) {
                processConnection();
            } else {
                System.out.println("conexão fechada pode destruir a thread");
            }

        } catch (IOException ex) {
            Logger.getLogger(ServidorSocketControl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ServidorSocketControl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
